/*
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef __VIDOPLAYER_H
#define __VIDOPLAYER_H

#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "esp_idf_version.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief 视频帧格式枚举
 *
 */
typedef enum {
    FORMAT_MJEPG = 0, // MJPEG格式
    FORMAT_H264,      // H264格式
} video_frame_format;

/**
 * @brief 视频帧信息结构体
 *
 */
typedef struct {
    uint32_t width;                  /*!< 图像宽度（像素） */
    uint32_t height;                 /*!< 图像高度（像素） */
    video_frame_format frame_format; /*!< 像素数据格式 */
} video_frame_info_t;

/**
 * @brief 音频帧格式枚举
 *
 */
typedef enum {
    FORMAT_PCM = 0, // PCM格式
} audio_frame_format;

/**
 * @brief 音频帧信息结构体
 *
 */
typedef struct {
    uint8_t channel;           /*!< 音频输出声道数 */
    uint8_t bits_per_sample;   /*!< 音频采样位数 */
    uint32_t sample_rate;      /*!< 音频采样率 */
    audio_frame_format format; /*!< 音频格式 */
} audio_frame_info_t;

/**
 * @brief 帧类型枚举：视频或音频
 *
 */
typedef enum {
    FRAME_TYPE_VIDEO = 0, // 视频帧
    FRAME_TYPE_AUDIO      // 音频帧
} frame_type_t;

/**
 * @brief 帧数据结构体
 *
 */
typedef struct {
    uint8_t *data;     /*!< 帧数据缓冲区指针 */
    size_t data_bytes; /*!< 帧数据缓冲区大小 */
    frame_type_t type; /*!< 帧类型：视频或音频 */
    /**
     * @brief 帧信息联合体
     *
     */
    union {
        video_frame_info_t video_info; /*!< 视频帧信息 */
        audio_frame_info_t audio_info; /*!< 音频帧信息 */
    };
} frame_data_t;

// 回调函数类型定义
typedef void (*video_write_cb)(frame_data_t *data, void *arg);                                // 视频帧写入回调函数
typedef void (*audio_write_cb)(frame_data_t *data, void *arg);                                // 音频帧写入回调函数
typedef void (*audio_set_clock_cb)(uint32_t rate, uint32_t bits_cfg, uint32_t ch, void *arg); // 音频时钟设置回调函数
typedef void (*avi_play_end_cb)(void *arg);                                                   // AVI播放结束回调函数

typedef void *avi_player_handle_t; // AVI播放器句柄类型

/**
 * @brief AVI播放器配置结构体
 *
 */
typedef struct {
    size_t buffer_size;                    /*!< 内部缓冲区大小 */
    video_write_cb video_cb;               /*!< 视频帧回调函数 */
    audio_write_cb audio_cb;               /*!< 音频帧回调函数 */
    audio_set_clock_cb audio_set_clock_cb; /*!< 音频时钟设置回调函数 */
    avi_play_end_cb avi_play_end_cb;       /*!< AVI播放结束回调函数 */
    UBaseType_t priority;                  /*!< FreeRTOS任务优先级 */
    BaseType_t coreID;                     /*!< ESP32核心ID */
    void *user_data;                       /*!< 用户数据指针 */
    int stack_size;                        /*!< 播放器任务堆栈大小 */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0)
    bool stack_in_psram; /*!< 是否在PSRAM中分配堆栈，如果从Flash读取文件/数据，不要设置为true */
#endif
} avi_player_config_t;

/**
 * @brief 从内存播放AVI文件。AVI的缓冲区将通过设置的回调函数传递。
 *
 * 此函数从内存缓冲区初始化和播放AVI文件。
 *
 * @param[in] handle AVI播放器句柄
 * @param[in] avi_data 指向内存中AVI文件数据的指针
 * @param[in] avi_size AVI文件数据的大小（字节）
 * @return esp_err_t 成功返回ESP_OK，否则返回错误代码
 */
esp_err_t avi_player_play_from_memory(avi_player_handle_t handle, uint8_t *avi_data, size_t avi_size);

/**
 * @brief 从文件系统播放AVI文件。AVI的缓冲区将通过设置的回调函数传递。
 *
 * 此函数使用文件名从文件系统初始化和播放AVI文件。
 *
 * @param[in] handle AVI播放器句柄
 * @param[in] filename 文件系统上AVI文件的路径
 * @return esp_err_t 成功返回ESP_OK，否则返回错误代码
 */
esp_err_t avi_player_play_from_file(avi_player_handle_t handle, const char *filename);

/**
 * @brief 从AVI流中获取一帧视频帧
 *
 * @param[in] handle AVI播放器句柄
 * @param[out] buffer        指向外部缓冲区的指针，用于保存一帧数据
 * @param[in,out] buffer_size 外部缓冲区的大小
 * @param[out] info          视频帧的信息
 * @param[in] ticks_to_wait  最大阻塞时间（滴答数）
 *
 * @return
 *      - ESP_OK           成功
 *      - ESP_ERR_TIMEOUT  超时
 *      - ESP_ERR_INVALID_ARG 参数为空
 *      - ESP_ERR_NO_MEM   外部缓冲区不足
 */
esp_err_t avi_player_get_video_buffer(avi_player_handle_t handle, void **buffer, size_t *buffer_size, video_frame_info_t *info, TickType_t ticks_to_wait);

/**
 * @brief 从AVI文件中获取音频缓冲区
 *
 * @param[in] handle AVI播放器句柄
 * @param[out] buffer 指向音频缓冲区的指针
 * @param[in] buffer_size 音频缓冲区的大小
 * @param[out] info 音频帧信息
 * @param[in] ticks_to_wait 最大阻塞时间（滴答数）
 *
 * @return
 *      - ESP_OK 成功
 *      - ESP_ERR_TIMEOUT 在超时前未获取到信号量
 *      - ESP_ERR_INVALID_ARG 缓冲区或信息为空，或缓冲区大小为零
 *      - ESP_ERR_NO_MEM 缓冲区大小不足
 */
esp_err_t avi_player_get_audio_buffer(avi_player_handle_t handle, void **buffer, size_t *buffer_size, audio_frame_info_t *info, TickType_t ticks_to_wait);

/**
 * @brief 停止AVI播放器
 *
 * @param[in] handle AVI播放器句柄
 * @return
 *      - ESP_OK: 成功停止AVI播放器
 *      - ESP_ERR_INVALID_STATE: AVI播放器未在播放状态
 */
esp_err_t avi_player_play_stop(avi_player_handle_t handle);

/**
 * @brief 初始化AVI播放器
 *
 * @param[in] config AVI播放器配置
 * @param[out] handle 存储AVI播放器句柄的指针
 *
 * @return
 *      - ESP_OK: 成功
 *      - ESP_ERR_NO_MEM: 无法为AVI播放器分配内存
 *      - ESP_ERR_INVALID_STATE: AVI播放器已被初始化
 */
esp_err_t avi_player_init(avi_player_config_t config, avi_player_handle_t *handle);

/**
 * @brief 反初始化AVI播放器
 *
 * 此函数反初始化并清理AVI播放器使用的资源。
 *
 * @param[in] handle AVI播放器句柄
 * @return esp_err_t 成功返回ESP_OK，否则返回错误代码
 */
esp_err_t avi_player_deinit(avi_player_handle_t handle);

#ifdef __cplusplus
}
#endif

#endif